﻿/// <reference path="jquery-1.7.1.js" />


//////////////////////////////////////////////////////////////////////////
// AralNovel class
//////////////////////////////////////////////////////////////////////////
function AralNovel() {

	this.hash = undefined;
	this.vars = {};
	this.layers = {};
	this.images = {};
	this.buttons = {};
	this.viewportElement = null;
	this.input = null;
	this.script = null;
	this.bgm = null;
	this.sysmenu = null;
	var _ANDefault_textbox_margin = "10px 10px 10px 10px";
	var _ANDefault_textbox_padding = "5px 5px 5px 5px";
	var _ANDefault_textbox_color = "#000";
	var _ANDefault_viewport_width = "640px";
	var _ANDefault_viewport_height = "480px";
	var _ANDefault_textbox_opacity = 0.4;
	var _ANDefault_font_size = 20;
	var _ANDefault_font_family = "Malgun Gothic,Gothic,Arial"; // "맑은 고딕";
	//var _ANDefault_bgm_volume = 0.5;

	var _this = this;
	var _isCleanMode = false;
	var _isBacklogMode = false;
	var _enableFunctionalities = { cleanMode: true, backlogMode: true, sysMenu: true };

	// initializer
	this.init = function (_viewportElement, _script) {

		try {
			_this.viewportElement = _viewportElement;
			_viewportElement.className = "ANViewport";

			// Initialize an input manager
			_this.input = new ANInput(_this.viewportElement);
			_this.input.onMouseClick = onMouseClick;
			_this.input.onMouseScroll = onMouseScroll;
			_this.viewportElement.ondragstart = function () { return false; };
			_this.viewportElement.onselectstart = function () { return false; };

			// Load Config Data
			_this.loadConfigData();

			// Set CSS rules
			AN_CreateCssRule(".ANViewport img", "background-color:transparent !important;"
											+ "border-top:none !important;"
											+ "border-right:none !important;"
											+ "border-bottom:none !important;"
											+ "border-left:none !important;"
											+ "-moz-box-shadow:none !important;"
											+ "-webkit-box-shadow:none !important;"
											+ "box-shadow:none !important;"

			); //!important
			AN_CreateHorizontalTextButtonCssRule(".choiceTextButtonBackground", 42, 64, 102, 0.95, 0);
			AN_CreateHorizontalGradationCssRule(".choiceTextButtonBackgroundLeft", 42, 64, 102, 0, 0.95);
			AN_CreateHorizontalGradationCssRule(".choiceTextButtonBackgroundCenter", 42, 64, 102, 0.95, 0.95);
			AN_CreateHorizontalGradationCssRule(".choiceTextButtonBackgroundRight", 42, 64, 102, 0.95, 0);

			// Set view-port size // will be replaced with # directives
			$(_this.viewportElement).css("width", _ANDefault_viewport_width)
								.css("height", _ANDefault_viewport_height)
								.css("overflow", "hidden")
								.css("position", "relative")
								.css("padding", "0")
								.css("textAlign", "left")
								.css("-webkit-tap-highlight-color", "rgba(0,0,0,0)");

			// For getting script from other urls
			_this.iframe = $("<iframe src='about:blank' width='0' height='0' style='visibility:hidden;z-index:0;position:absolute;'></iframe>")
						.appendTo("body")

			// Create background layer
			_this.layers["bg"] = $("<div></div>").appendTo(_this.viewportElement);

			// Create characters layer
			_this.layers["ch"] = $("<div></div>").appendTo(_this.viewportElement);

			// Create text-background layer
			_this.layers["textbg"] = $("<div></div>").appendTo(_this.viewportElement);
			_this.textboxMargin = _ANDefault_textbox_margin; // Set default
			_this.textboxPadding = _ANDefault_textbox_padding; // Set default

			// Create text layer
			_this.layers["text"] = $("<div></div>").appendTo(_this.viewportElement);

			// Create button layer
			_this.layers["btn"] = $("<div></div>").appendTo(_this.viewportElement);

			// Create default button area
			_this.layers["btncenter"] = $("<div></div>").appendTo(_this.layers["btn"]);

			// Create backlog-background layer
			_this.layers["backlogbg"] = $("<div></div>").appendTo(_this.viewportElement);

			// Create backlog layer
			_this.layers["backlog"] = $("<div></div>").appendTo(_this.layers["backlogbg"]);

			// BGM
			_this.bgm = new ANBGM(_this);
			_this.bgm.setVolume(1);

			// System Menu
			_this.sysmenu = new ANSysmenu(_this);

			// Storages
			//for (var i = 0; i < _this.storages.length; i++) {
			//	_this.storages[i] = new (_this.storages[i])(_this);
			//}

			//////////////////////////////
			// Initialize script object
			_this.script = new ANScript(_this);
			_this.script.parseANScript(_script); // Parse a novel script
			_this.hash = hex_sha1(_this.script.info.title);
			//if (_this.script.info.viewportWidth) $(_this.viewportElement).css("width", _this.script.info.viewportWidth);
			//if (_this.script.info.viewportHeight) $(_this.viewportElement).css("height", _this.script.info.viewportHeight);

			// Initialize CSS of layers
			_this.resetLayers();
			//_this.adjustLayerSizes();

			AralNovel.prototype.novels.push(this);

			// Run
			_this.script.run();
		}
		catch (ex) {
			throw ex;
		}
	}

	this.resetLayers = function () {
		// Background Layer
		this.layers["bg"].css({
			zIndex: 100,
			position: "absolute",
			padding: 0,
			margin: 0,
			top: 0,
			left: 0,
			width: "100%",
			height: "100%",
			textAlign: "left",
			overflow: "hidden",
			backgroundColor: "Black",
			backgroundImage: "none"
		});
		this.layers['bg'].empty(); 		// Clear BG

		// Character Layer
		_this.layers["ch"].css({
			zIndex: 200,
			position: "absolute",
			padding: 0,
			margin: 0,
			top: 0,
			left: 0,
			width: "100%",
			height: "100%",
			textAlign: "left",
			overflow: "hidden"
		});

		// Text-background layer
		_this.layers["textbg"].css({
			zIndex: 300,
			position: "absolute",
			textAlign: "left",
			overflow: "hidden",
			backgroundColor: "Black",
			backgroundImage: "none",
			opacity: _ANDefault_textbox_opacity
		});

		// Text layer
		_this.layers["text"].css({
			zIndex: 400,
			position: "absolute",
			left: 0,
			top: 0,
			textAlign: "left",
			overflow: "hidden",
			color: "White",
			wordBreak: "break-all", 		// Internet Explorer 5.5+
			whiteSpace: "pre-wrap", 		// CSS3
			whiteSpace: "-moz-pre-wrap", // Mozilla, since 1999 
			whiteSpace: "-pre-wrap", 		// Opera 4-6
			whiteSpace: "-o-pre-wrap", 		// Opera 7 
			fontWeight: "bold",
			fontFamily: _ANDefault_font_family,
			fontSize: _ANDefault_font_size,
			textShadow: ($.browser.msie ? "" : "1px 1px 2px Black")
		})
	.css("word-wrap", "break-all")
	.html("<!--TextTailMark-->"); // Clear text
		_this.layers["text"][0].style.wordBreak = "break-all";

		if ((/(px)$/i).test(_this.layers["text"][0].style.fontSize)) {
			var fontSize = _this.layers["text"][0].style.fontSize.replace(/(px)$/i, "");
			_this.layers["text"].css("lineHeight", Math.round(eval(fontSize) * 1.3) + "px");
		}

		// Button layer
		_this.layers["btn"].css({
			zIndex: 500,
			position: "absolute",
			padding: 0,
			margin: 0,
			top: 0,
			left: 0,
			width: "100%",
			height: "100%",
			overflow: "hidden"
		});

		// Default button area
		_this.layers["btncenter"].css({
			position: "relative",
			padding: 0,
			margin: 0,
			left: "50%",
			top: "50%",
			width: "80%",
			textAlign: "center",
			overflow: "visible"
		});

		// Create backlog-background layer
		_this.layers["backlogbg"].css({
			zIndex: 600,
			position: "absolute",
			padding: 0,
			margin: 0,
			left: 0,
			top: 0,
			width: "100%",
			height: "100%",
			textAlign: "left",
			backgroundColor: "#224422",
			overflowY: "scroll",
			display: "none",
			opacity: 0.85
		});

		// Backlog layer
		_this.layers["backlog"].css({
			position: "absolute",
			padding: "10px",
			margin: 0,
			left: 0,
			top: 0,
			width: "95%",
			textAlign: "left",
			wordBreak: "break-all", 		// Internet Explorer 5.5+
			whiteSpace: "pre-wrap", 		// CSS3
			whiteSpace: "-moz-pre-wrap", // Mozilla, since 1999 
			whiteSpace: "-pre-wrap", 		// Opera 4-6
			whiteSpace: "-o-pre-wrap", 		// Opera 7 
			color: _this.layers["text"].css("color"),
			fontWeight: _this.layers["text"].css("fontWeight"),
			fontFamily: _this.layers["text"].css("fontFamily"),
			fontSize: _this.layers["text"].css("fontSize"),
			textShadow: ($.browser.msie ? "" : _this.layers["text"].css("textShadow"))
		});

		// Clear Image Layer
		this.clearAllImages();

		// Clear Button Layer
		this.clearAllButtons();

		// Restore default textbox size
		this.textboxMargin = _ANDefault_textbox_margin;
		this.textboxPadding = _ANDefault_textbox_padding;
		this.adjustLayerSizes();

		// Enable all functionalities
		this.enableFunctionalities(true, true, true);

		// Stop BGM
		this.bgm.stop();
		this.bgm.setVolume(1);

	}

	this.enableFunctionalities = function (_cleanMode, _backlogMode, _sysmenuMode) {
		if (_cleanMode != undefined) _enableFunctionalities.cleanMode = _cleanMode;
		if (_backlogMode != undefined) _enableFunctionalities.backlogMode = _backlogMode;
		if (_sysmenuMode != undefined && _enableFunctionalities.sysMenu != _sysmenuMode) {
			this.sysmenu.showIcon(_sysmenuMode);
			_enableFunctionalities.sysMenu = _sysmenuMode;
		}
	}

	this.adjustLayerSizes = function () {
		// textbg layer
		this.layers["textbg"].css({
			width: "100%",
			height: "100%",
			margin: 0,
			padding: this.textboxMargin
		});
		this.layers["textbg"].css({
			width: (this.layers["textbg"].outerWidth() > this.layers["bg"].width()) ? this.layers["bg"].width() * 2 - this.layers["textbg"].outerWidth() : this.layers["textbg"].width(),
			height: (this.layers["textbg"].outerHeight() > this.layers["bg"].height()) ? this.layers["bg"].height() * 2 - this.layers["textbg"].outerHeight() : this.layers["textbg"].height(),
			marginTop: this.layers["textbg"].css("paddingTop"),
			marginRight: this.layers["textbg"].css("paddingRight"),
			marginBottom: this.layers["textbg"].css("paddingBottom"),
			marginLeft: this.layers["textbg"].css("paddingLeft"),
			padding: 0
		});

		// text layer
		this.layers["text"].css({
			width: this.layers["textbg"].width(),
			height: this.layers["textbg"].height(),
			marginTop: this.layers["textbg"].css("marginTop"),
			marginRight: this.layers["textbg"].css("marginRight"),
			marginBottom: this.layers["textbg"].css("marginBottom"),
			marginLeft: this.layers["textbg"].css("marginLeft"),
			padding: this.textboxPadding
		});
		this.layers["text"].css({
			width: this.layers["textbg"].width() * 2 - this.layers["text"].outerWidth(),
			height: this.layers["textbg"].height() * 2 - this.layers["text"].outerHeight()
		});

	}

	this.getSaveScript = function () {
		var strSaveScript = "";

		// game info
		strSaveScript += "/*metadata-url:" + _this.script.info.url + ":metadata-url*/\r\n";
		strSaveScript += "/*metadata-title:" + _this.script.info.title + ":metadata-title*/\r\n";
		strSaveScript += "/*metadata-part:" + _this.script.info.part + ":metadata-part*/\r\n";

		// save datetime
		strSaveScript += "/*metadata-datetime:" + (new Date()).toLocaleString() + ":metadata-datetime*/\r\n";

		// Background Layer
		strSaveScript += "_this.setBG('" + _this.layers['bg'].children("._AN_BGIMG").attr("src") + "',0);\r\n";
		strSaveScript += "/*metadata-bg:" + _this.layers['bg'].children("._AN_BGIMG").attr("src") + ":metadata-bg*/\r\n";

		// Text Layer
		var _textboxPadding = _this.layers['text'].css("paddingTop")
				+ " " + _this.layers['text'].css("paddingRight")
				+ " " + _this.layers['text'].css("paddingBottom")
				+ " " + _this.layers['text'].css("paddingLeft");
		var _textboxMargin = _this.layers['text'].css("marginTop")
				+ " " + _this.layers['text'].css("marginRight")
				+ " " + _this.layers['text'].css("marginBottom")
				+ " " + _this.layers['text'].css("marginLeft");

		strSaveScript += "_this.layers['textbg'].css({"
		strSaveScript += "backgroundColor:'" + _this.layers['textbg'].css("backgroundColor") + "',";
		strSaveScript += "backgroundImage:'" + _this.layers['textbg'].css("backgroundImage") + "',";
		strSaveScript += "opacity:'" + _this.layers['textbg'].css("opacity") + "'});\r\n";

		strSaveScript += "_this.layers['text'].css({\r\n"
		strSaveScript += "color:'" + _this.layers['text'].css("color") + "',\r\n";
		strSaveScript += "fontWeight:'" + _this.layers['text'].css("fontWeight") + "',\r\n";
		strSaveScript += "fontFamily:'" + _this.layers['text'].css("fontFamily").replace(/['"]/g, "") + "',\r\n";
		strSaveScript += "fontSize:'" + _this.layers['text'].css("fontSize") + "'})\r\n";
		strSaveScript += ".html(" + _this.script.wrapCommandArgument(_this.layers['text'].html().replace(/[\r\n]/g, " ").replace(/(<!--TextTailMark-->).*/g, "")) + ");\r\n";
		strSaveScript += "/*metadata-text:" + _this.layers['text'].text().replace(/[\r\n]/g, "") + ":metadata-text*/\r\n";
		strSaveScript += "_this.textboxMargin='" + _textboxMargin + "';\r\n"
		strSaveScript += "_this.textboxPadding='" + _textboxPadding + "';\r\n"
		strSaveScript += "_this.adjustLayerSizes();\r\n"

		// Images ('ch' Layer)
		for (var img_id in _this.images) {
			if (_this.images[img_id]) {
				strSaveScript += "_this.script.executeCommand(new ANCmd_setimg(_this"
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(img_id))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(_this.images[img_id].attr("src")))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(_this.images[img_id].data("parentLayerId")))
							+ "));\r\n"
				strSaveScript += "_this.script.executeCommand(new ANCmd_img(_this"
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(img_id))
							+ ",'0'"
							+ ",'" + _this.images[img_id].css("left").replace(/(px)$/i, "") + "'"
							+ ",'" + _this.images[img_id].css("top").replace(/(px)$/i, "") + "'"
							+ ",'" + _this.images[img_id].css("opacity") + "'"
							+ "));\r\n";
			}
		}

		// Button Layer
		for (var btn_id in _this.buttons) {
			var jqBtn = _this.buttons[btn_id];
			if (jqBtn) {
				strSaveScript += "_this.script.executeCommand(new ANCmd_textbutton(_this"
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(btn_id))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(jqBtn.data("command").text))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(jqBtn.data("command").url))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(jqBtn.data("command").x))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(jqBtn.data("command").y))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(jqBtn.data("command").width))
							+ "," + _this.script.wrapCommandArgument(_this.script.wrapCommandArgument(jqBtn.data("command").height))
							+ "));\r\n";
				strSaveScript += "_this.buttons[" + _this.script.wrapCommandArgument(btn_id) + "].data('isChoiceButton'," + jqBtn.data("isChoiceButton") + ");\r\n";
			}
		}

		// BGM
		if (_this.bgm.getSrc()) {
			strSaveScript += "_this.bgm.play('" + _this.bgm.getSrc() + "');\r\n"
			strSaveScript += "_this.bgm.setVolume('" + _this.bgm.getVolume() + "');\r\n"
			if (_this.bgm.isStoped()) ("_this.bgm.stop();\r\n");
		}

		// Enable functionalities
		strSaveScript += "_this.enableFunctionalities("
						+ _enableFunctionalities.cleanMode.toString() + ","
						+ _enableFunctionalities.backlogMode.toString() + ","
						+ _enableFunctionalities.sysMenu.toString() + ");\r\n"

		// Choice Mode
		strSaveScript += "_this.isChoiceMode=" + _this.isChoiceMode + ";\r\n";

		// commandList Index
		strSaveScript += "_this.script.curOffset=" + _this.script.curOffset + ";\r\n";

		return strSaveScript;
	}

	this.executeLoadScript = function (strLoadScript) {
		if (!strLoadScript) throw "No data to load!";

		// Stop script running
		this.script.stop();

		// Reset all layers
		this.resetLayers();

		// Extract url info
		var url;
		var title;
		var part;
		if ((/.*\/\*metadata-url:(.*):metadata-url\*\/.*/).test(strLoadScript))
			url = strLoadScript.replace(/[\r\n]/g, "").replace(/.*\/\*metadata-url:(.*):metadata-url\*\/.*/, "$1");
		if ((/.*\/\*metadata-title:(.*):metadata-title\*\/.*/).test(strLoadScript))
			title = strLoadScript.replace(/[\r\n]/g, "").replace(/.*\/\*metadata-title:(.*):metadata-title\*\/.*/, "$1");
		if ((/.*\/\*metadata-part:(.*):metadata-part\*\/.*/).test(strLoadScript))
			part = strLoadScript.replace(/[\r\n]/g, "").replace(/.*\/\*metadata-part:(.*):metadata-part\*\/.*/, "$1");

		if (url != this.script.info.url || part != this.script.info.part) {
			this.script.jump(url, part, function () {
				// Execute load script
				eval(strLoadScript);
				_this.adjustLayerSizes();
			});
		}
		else {
			// Execute load script
			eval(strLoadScript);

			// Run script
			this.adjustLayerSizes();
			this.script.run();
		}

	}

	this.newGame = function () {
		// Stop script running
		this.script.stop();

		// Reset all layers
		this.resetLayers();


		if (this.script.rootinfo.url != this.script.info.url || this.script.rootinfo.part != this.script.info.part) {
			this.script.jump(this.script.rootinfo.url, this.script.rootinfo.part, function () {
				// Execute load script
				//eval(strLoadScript);
				//_this.adjustLayerSizes();
			});
		}
		else {
			// New Game
			this.script.curOffset = 0; 		// Set script offset to 0
			this.isChoiceMode = false; 		// Disable choice mode

			// Run script
			this.script.run();
		}

	}

	this.saveConfigData = function () {
		for (var i = 0; i < this.storages.length; i++) {
			var strg = this.storages[i];
			if (strg.errorDescription != undefined) continue;

			strg.write("AralNovelConfigData_TextSpeed", this.config.textSpeed);
			strg.write("AralNovelConfigData_BGMVolume", this.config.bgmVolume);
			strg.write("AralNovelConfigData_SEVolume", this.config.seVolume);
		}
	}

	this.loadConfigData = function () {
		for (var i = 0; i < this.storages.length; i++) {
			var strg = this.storages[i];
			if (strg.errorDescription != undefined) continue;

			var textSpeed = strg.read("AralNovelConfigData_TextSpeed");
			if(textSpeed != undefined) this.config.textSpeed = eval(textSpeed);
			
			var bgmVolume = strg.read("AralNovelConfigData_BGMVolume");
			if (bgmVolume != undefined) this.config.bgmVolume = eval(bgmVolume);
			
			var seVolume = strg.read("AralNovelConfigData_SEVolume");
			if (seVolume != undefined) this.config.seVolume = eval(seVolume);

			break;
		}
	}

	this.clearAllImages = function () {
		for (var img_id in _this.images) {
			if (this.images[img_id] != undefined) {
				this.images[img_id].hide().remove();
				this.images[img_id] = undefined;
			}
		}
	}


	this.clearAllButtons = function () {
		for (var btn_id in _this.buttons) {
			if (this.buttons[btn_id] != undefined) {
				this.buttons[btn_id].hide().remove();
				this.buttons[btn_id] = undefined;
			}
		}
	}


	this.clearChoiceButtons = function () {
		for (var btn_id in _this.buttons) {
			if (this.buttons[btn_id] != undefined && this.buttons[btn_id].data("isChoiceButton")) {
				this.buttons[btn_id].hide().remove();
				this.buttons[btn_id] = undefined;
			}
		}
	}

	this.setVolumnBGM = function (vol) {
		alert("Not implemented, yet!");
	}

	this.setVolumnVoice = function (vol) {
		alert("Not implemented, yet!");
	}

	this.setTextSpeed = function (spd) {
		alert("Not implemented, yet!");
	}

	this.setBG = function (src, delay, type, callback) {
		var bgLayer = this.layers["bg"];
		if (delay == undefined) delay = 1000;
		if (type == undefined) type = 0;

		// Create dummy layer on the "bg" layer
		var dummyLayer = $("<div></div>")
				.appendTo(bgLayer)
				.css({
					position: "absolute",
					padding: 0,
					margin: 0,
					top: 0,
					left: 0,
					width: "100%",
					height: "100%",
					zIndex: 2,
					backgroundColor: "Black"
				})
				.append(bgLayer.children("._AN_BGIMG").clone().css("zIndex", 3))
				.addClass("_AN_DUMMY_BG")
		;

		// Change image src of "bg" layer
		bgLayer.children("._AN_BGIMG").remove();
		if (src) {
			var newImg = $("<img>")
			.css({
				position: "absolute",
				zIndex: 1,
				border: 0,
				padding: 0,
				margin: 0
			})
			.insertBefore(dummyLayer)
			.addClass("_AN_BGIMG")
			.load(function () {

				// Adjust image size
				$(this).css({
					left: 0,
					top: 0,
					width: bgLayer.width(),
					height: bgLayer.height(),
					cursor: "default"
				});

				// Start animation
				bgLayer.children("._AN_DUMMY_BG").fadeOut(delay, function () {
					if (callback) callback();
					bgLayer.children("._AN_DUMMY_BG").remove();
				});
			})
			.error(function () {
				if (callback) callback();
				dummyLayer.remove();
				$(this).remove();
			})

			//newImg[0].onloadstart = function () {  alert(" Show the progress bar. "); };
			//newImg[0].onprogress = function (e) { alert(" Update the progress bar. "); };
			//newImg[0].onload = function () { alert(" Load succeeded. Add the image element to the page. "); };
			//newImg[0].onerror = function () { alert(" Load failed. Show a custom error message. "); };
			//newImg[0].onloadend = function () { alert(" Load either either succeeded or failed. Either way, hide the progress bar. "); };
			newImg[0].src = src;
		}
		else {
			// Start animation
			dummyLayer.fadeOut(delay, function () {
				if (callback) callback();
				dummyLayer.remove();
			});
		}
	}             // end of setBG()

	this.eval = function (js) {
		var version = _this.version;
		var viewportElement = _this.viewportElement;
		var layers = _this.layers;
		var images = _this.images;
		var input = _this.input;
		var script = _this.script;
		var bgm = _this.bgm;
		js = js.replace(eval("/^" + String.fromCharCode(8220) + "|" + String.fromCharCode(8221) + "$/g"), '\"');
		js = js.replace(eval("/^" + String.fromCharCode(8216) + "|" + String.fromCharCode(8217) + "$/g"), '\'');
		return eval(js);
	}

	//////////////////////////////////////////////////////////////////////////////
	// Internal Functions
	//////////////////////////////////////////////////////////////////////////////

	// Mouse Click Event Handler
	function onMouseClick(x, y, btn) {

		if (_isCleanMode)	// in functional mode (backlog/clean/systemmenu)
		{
			if (btn == 1 || btn == 3) {
				setBacklogMode(false);
				setCleanMode(false);
			}
		}
		else // in play mode
		{
			if (btn == 1) {
				if (_this.script.curOffset < _this.script.commandList.length
				&& _this.script.commandList[_this.script.curOffset]) {
					_this.script.commandList[_this.script.curOffset].onClick();
				}
			}
			else if (btn == 2 && _enableFunctionalities.backlogMode) {
				setCleanMode(true);
				setBacklogMode(true);
			}
			else if (btn == 3 && _enableFunctionalities.cleanMode) {
				setCleanMode(true);
			}
		}
	}

	// Mouse Scroll Event Handler
	function onMouseScroll(delta, absolute) {

		if (_isBacklogMode) {
			var unitSize = 20;
			try {
				unitSize = eval(_this.layers["backlog"].css("fontSize").replace(/(px)$/i, ""));
			} catch (ex) { }
			var prevScrollTop = _this.layers["backlogbg"].scrollTop();
			_this.layers["backlogbg"].scrollTop(prevScrollTop - (unitSize * delta));

			// if scroll position is the end
			if (delta < 0 && _this.layers["backlogbg"].scrollTop() == prevScrollTop) {
				setBacklogMode(false);
				setCleanMode(false);
			}
		}
		
		if (_this.sysmenu.isShowing()) {
			return;
		}
		else if (delta > 0 && _enableFunctionalities.backlogMode) {
			setCleanMode(true);
			setBacklogMode(true);
		}
	}

	// Switch On/Off the text layer visibility
	function setCleanMode(flag) {
		if (flag == _isCleanMode) return;

		_isCleanMode = flag;

		// Link dummy event handler
		_this.input.onMouseClick = function () { };
		_this.input.onMouseScroll = function () { };

		// Pause/Resume script
		_this.script[flag ? "pause" : "resume"]();

		// show/hide Sysmenu Icon
		_this.sysmenu.showIcon(!flag && _enableFunctionalities.sysMenu);

		// Fade animation
		_this.layers["btn"][flag ? "fadeOut" : "fadeIn"](300);
		_this.layers["text"][flag ? "fadeOut" : "fadeIn"](300);
		_this.layers["textbg"][flag ? "fadeOut" : "fadeIn"](300, function () {
			_this.input.onMouseClick = onMouseClick;
			_this.input.onMouseScroll = onMouseScroll;
		});
	} // end of setCleanMode()


	// Switch On/Off the back-log mode
	function setBacklogMode(flag) {
		if (flag == _isBacklogMode) return;

		_isBacklogMode = flag;
		var layerBackLogBG = _this.layers["backlogbg"];
		if (flag) {
			// Fade animation
			layerBackLogBG.fadeIn(400);

			// Set scroll position
			layerBackLogBG[0].scrollTop = layerBackLogBG[0].scrollHeight - layerBackLogBG[0].clientHeight;
		}
		else {
			// Fade animation
			layerBackLogBG.fadeOut(400);
		}

	} // end of setBacklogMode()

}; // end of AralNovel class



//////////////////////////////////////////////////////////////////////////
// AralNovel boot loader
//////////////////////////////////////////////////////////////////////////
function _AN_OnLoad() {


	// for IE6
	if ($.browser.msie && $.browser.version == "6.0") {
		$.getScript('http://www.arallab.com/aralnovel/js/DD_belatedPNG_0.0.8a-min.js', function (data, textStatus, jqxhr) {
			DD_belatedPNG.fix("img");
		})
	}

	// Get JQuery-UI CSS
	//AN_GetCSS("css/jquery-ui-1.8.18.custom.css");


	// Parse a HTML (It returns an array which contains DOM removal information.)
	function _AN_TraverseHtml() {
		var arrRemovalInfo = [];
		var _curRemovalInfo = undefined;
		var _defNewLineTags = ["BR", "DIV", "P"];


		function findAralNovelDirective($RootElem) {
			var _ANPureScript = "";

			try {
				// Traverse all nodes
				$RootElem.contents().each(function (idx, elem) { // for (var i = 0; i < $RootElem.childNodes.length; i++) {
					var $child = $(this); //objRootElem.childNodes[i];	
					var nodeName = elem.nodeName.toUpperCase();

					if (_curRemovalInfo == undefined) {
						if (nodeName == "#TEXT" && (/^(#aralnovelbegin)/i).test($child.text().trim())) {
							_curRemovalInfo = { beginElement: $child[0] };
						}
						else {
							_ANPureScript += findAralNovelDirective($child);
							return;
						}
					}

					var subResult = "";

					// Text node
					if (nodeName == "#TEXT") {
						subResult = $child.text().trim();

						if ((/^(#aralnovelend)/i).test(subResult)) {
							subResult = "\r\n#aralnovelend\r\n";
							_curRemovalInfo["endElement"] = $child[0];
						}
					}
					// Other cases (html element/comments/etc...)
					else {
						// Add #label if it is <a name'...'> tag
						if (nodeName.toUpperCase() == "A"
							&& $child.attr("name") != undefined
							&& $child.attr("name").trim() != "") {
							subResult += ("\r\n#label " + $child.attr("name").trim());
						}

						// Recursive calling of parseHtmlScenario
						var childrenResult = findAralNovelDirective($child);
						if (childrenResult) subResult += childrenResult;

						// Add "\r\n" if it is a kind of new line tag
						if (_defNewLineTags.contains(nodeName)) {
							subResult += "\r\n";
						}
						// Add [bg] command if it is <img> tag
						else if (nodeName == "IMG") {
							subResult += ("\r\n[bg \"" + $child.attr("src") + "\"]");
						}
						// Add [wait] command if it is <hr> tag
						else if (nodeName == "HR") {
							subResult += ("[wait][clear]");
						}
					}

					_ANPureScript += subResult;

					// Correction
					_ANPureScript = _ANPureScript.replace(/[\r\n]+(\[wait\]\[clear\])/g, "[wait][clear]"); 	// Remove a new line just before '[wait][clear]'
					_ANPureScript = _ANPureScript.replace(/(\[[ \t\r\n]*setimg[^\[\]]+)\[bg (\"[^\"\]]*\")\]([^\[\]]*\])/g, "$1$2$3"); // Allow to use img tag as a command argument.

					// Check the current script is available to make a novel
					if ((/^(#aralnovelbegin)/i).test(_ANPureScript) && (/(\r\n#aralnovelend\r\n)/i).test(_ANPureScript)) {
						var endIdx = _ANPureScript.search(/(\r\n#aralnovelend\r\n)/i) + 17;
						_curRemovalInfo["novelScript"] = _ANPureScript.substr(0, endIdx);
						arrRemovalInfo.push(_curRemovalInfo);
						_curRemovalInfo = undefined;
						_ANPureScript = "";
					}
				});                         //end of contents

			}
			catch (ex) {
				ex = ex;
			}

			return _ANPureScript;
		}

		findAralNovelDirective($("body"));
		return arrRemovalInfo;

	} // end of _AN_TraverseHtml()

	function _AN_RemoveElementsFromScreen(_beginElem, _endElem) {
		var _bIsBeingDeleted = false;
		var _bIsCompleted = false;

		function RemoveRecursive($RootElem) {
			try {
				$RootElem.contents().each(function (idx, elem) {
					if (_bIsCompleted) return false;
					var $child = $(this);

					if (_bIsBeingDeleted === false) {
						if ($child.is(_beginElem)) {
							_bIsBeingDeleted = true;
							$child.hide();
							$child.remove();
						}
						else if ($child.contents().length > 0) {
							RemoveRecursive($child);
							if ($child.contents().length == 0) {
								$child.hide();
								$child.remove();
							}
						}
					}
					else {
						if ($child.is(_endElem)) {
							$child.hide();
							$child.remove();
							_bIsBeingDeleted = false;
							_bIsCompleted = true;
							return false;
						}
						else if ($child.contents().length > 0) {
							RemoveRecursive($child);
							if ($child.contents().length == 0) {
								$child.hide();
								$child.remove();
							}
						}
						else {
							$child.hide();
							$child.remove();
						}
					}
				});
			} catch (ex) { }
		}

		RemoveRecursive($("body"));
	}

	//debugLogs("[AN] _AN_OnLoad start");
	var arrRemovalInfo = _AN_TraverseHtml();
	var arrScripts = convertHtmlToANScript($("body").html());

	// Parse #aralnovelbegin directives
	var loadedUri = parseUri(location.toString());
	for (var i = 0; i < arrRemovalInfo.length && i < arrScripts.length; i++) {
		arrRemovalInfo[i].title = loadedUri.authority;
		arrRemovalInfo[i].part = "";

		var strToken = null;
		//var matches = arrScripts[i].match(/#aralnovelbegin\s+\"(.*?)\"\s*?,\s*?\"(.*?)\".*/i);
		var matches = arrScripts[i].match(/#aralnovelbegin\s+\"(.*?)\".*/i);
		if (matches && matches.length > 1) {
			arrRemovalInfo[i].title = matches[1].trim();
		}
		matches = arrScripts[i].match(/#aralnovelbegin\s+\"(?:.*?)\"\s*?,\s*?\"(.*?)\".*/i);
		if (matches && matches.length > 1) {
			arrRemovalInfo[i].part = matches[1].trim();
		}
	}

	// Check parent's waiting
	try {
		var win = (window == top ? null : window.parent);
		while(arrScripts.length > 0 && win) {

			try {
				if (win.AralNovel != undefined && win.AralNovel.prototype.novels != undefined) {
					for (var j = 0; j < win.AralNovel.prototype.novels.length; j++) {
						var novel = win.AralNovel.prototype.novels[j];
						for (var i = 0; novel.script.waiting && i < arrRemovalInfo.length && i < arrScripts.length; i++) {
							// Check title and part
							if (novel.script.waiting.title != arrRemovalInfo[i].title) continue;
							if (novel.script.waiting.part && novel.script.waiting.part != arrRemovalInfo[i].part) continue;

							// Post ANScript
							novel.script.postANScript(arrScripts[i], loadedUri.relative);

							// Clear iframe contents
							if (novel.iframe) {
								novel.iframe.attr("src", "about:blank");
							}

							return;
						}
					}
				}
			} catch (ex1) { }

			if(win == top) break;
			win = win.parent;
		}
	} catch (ex) { }

	// Generate Aral Novel Screens
	for (var i = 0; i < arrRemovalInfo.length && i < arrScripts.length; i++) {
		var si = arrRemovalInfo[i];
		try {
			var an_viewport = $("<div id='ANViewport" + i + "'></div>").insertBefore(si.beginElement);

			// Hide script elements
			_AN_RemoveElementsFromScreen(si.beginElement, si.endElement);

			var an = new AralNovel();
			an.init(an_viewport[0], arrScripts[i]);  //si.novelScript);
		}
		catch (ex) {
		}
	}
}

AralNovel.prototype.constructor = AralNovel;
AralNovel.prototype.storages = [];
AralNovel.prototype.novels = [];
AralNovel.prototype.config = {
	bgmVolume : 50,
	seVolume : 50,
	textSpeed : 50
};

if (!window._AralNovelBootLoader) {
	$(document).ready(function () {
		window._AralNovelBootLoader();
	});
}
window._AralNovelBootLoader = _AN_OnLoad;


//